using System;
using System.Linq;
using System.Reflection;
using System.Text;
using InterfaceLiftLib.Attributes;
using InterfaceLiftLib.Extensions;
using InterfaceLiftLib.Service.Interfaces;

namespace InterfaceLiftLib.Service.Implementations
{
    /// <summary>
    /// 
    /// </summary>
    public class CamelCaseUrlBuilder : IUrlBuilder
    {
        public string BuildUrl(string baseUrl, MethodInfo methodInfo, params object[] args)
        {
            if (String.IsNullOrEmpty(baseUrl))
                throw new ArgumentNullException("baseUrl");

            if (methodInfo == null) 
                throw new ArgumentNullException("methodInfo");

            var parametersInfo = methodInfo.GetParameters();
            if (args.Length > parametersInfo.Length)
                throw new ArgumentException("Number of args is higher than the number of parameters declared in methodInfo");

            //getting web service method name using WebServiceMethodNameAttribute attribute..            
            var webServiceMethodNameAttr = methodInfo.GetCustomAttributes(typeof(WebServiceMethodNameAttribute), false).FirstOrDefault() as WebServiceMethodNameAttribute;
            var webServiceMethodName = webServiceMethodNameAttr != null ? webServiceMethodNameAttr.WebServiceMethodName : methodInfo.Name;
            
            var urlBuilder = new StringBuilder((baseUrl.EndsWith("/") ? baseUrl : baseUrl + "/") + webServiceMethodName + "/");
            var paramsBuilder = new StringBuilder();

            for (var parameterIndex = 0; parameterIndex < args.Length; parameterIndex++)
            {
                var parameterInfo = parametersInfo[parameterIndex];
                var arg = args[parameterIndex];
                string argValue;
                EnumConverterAttribute enumConverterAttribute;
                if (parameterInfo.ParameterType.IsEnum && parameterInfo.TryGetCustomAttribute(out enumConverterAttribute))
                {
                    var enumConverter = (IQueryStringEnumToStringConverter)Activator.CreateInstance(enumConverterAttribute.EnumConverterType);
                    argValue = enumConverter.GetStringValue(arg);
                }
                else
                {
                    argValue = arg != null ? Uri.EscapeUriString(arg.ToString()) : null;
                }

                //if the parameter has the "QueryStringParameter" attribute, it has to be appended to the 
                //paramsBuilder object..
                if (parameterInfo.GetCustomAttributes(typeof (QueryStringParameterAttribute), false).Any())
                {
                    if (arg != null && !Object.Equals(arg.GetType().GetDefaultValue(), arg))
                    {
                        var argName = FromCamelCaseToWs(parameterInfo.Name);
                        paramsBuilder.Append(argName + "=" + argValue + "&");
                    }
                }
                else //..otherwise it has to be appended to the urlBuilder object.
                {
                    urlBuilder.Append(argValue + "/");
                }
            }

            return String.Format("{0}{1}", urlBuilder.ToString(),
                                 paramsBuilder.Length > 0 ? "?" + paramsBuilder.ToString().Substring(0, paramsBuilder.Length - 1) : String.Empty);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private static string FromCamelCaseToWs(string s)
        {
            var builder = new StringBuilder();
            foreach (var c in s)
            {
                if (Char.IsUpper(c))
                {
                    builder.Append("_" + Char.ToLower(c));
                }
                else
                {
                    builder.Append(c);
                }
            }
            return builder.ToString();
        }              
    }
}